import {ref} from 'vue'
import { ElMessage } from 'element-plus'
import { downloadFile } from '@/utils'
// 兼容浏览器的mediaDevices
// 老的浏览器可能根本没有实现 mediaDevices，所以我们可以先设置一个空的对象

if (navigator.mediaDevices === undefined) {
  navigator.mediaDevices = {}
}

// 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
// 因为这样可能会覆盖已有的属性。这里我们只会在没有 getUserMedia 属性的时候添加它。
if (navigator.mediaDevices.getUserMedia === undefined) {
  navigator.mediaDevices.getUserMedia = function (constraints) {

    // 首先，如果有 getUserMedia 的话，就获得它
    const getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia

    // 一些浏览器根本没实现它 - 那么就返回一个 error 到 promise 的 reject 来保持一个统一的接口
    if (!getUserMedia) {
      return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
    }

    // 否则，为老的 navigator.getUserMedia 方法包裹一个 Promise
    return new Promise(function (resolve, reject) {
      getUserMedia.call(navigator, constraints, resolve, reject)
    })
  }
}

/**
 * 创建摄像头各类操作
 * @param videoRef 实时录像显示
 * @returns {{openCamera: ((function(): Promise<void>)|*), stop: stop, start: start}}
 */
export const useVideo = (videoRef) => {
  // 程序是否有错误消息提示
  const errorMessage = ref('')
  // 抛错误
  const throwError = (message) => {
    errorMessage.value = message
    ElMessage.error(message)
  }

  // 摄像头对象
  const mediaStream = ref(null)
  // 截取到的视频流
  const recordedBlobs = ref([])

  // 打开摄像头 videoRef:摄像头投影dom元素
  const openCamera = async () => {
    muteVideo(videoRef)
    try {
      // 判断浏览器mediaDevices兼容支持情况
      if (navigator.mediaDevices) {
        const _mediaStream = await navigator.mediaDevices.getUserMedia({video: true, audio: true})
        // 旧的浏览器可能没有 srcObject
        if ('srcObject' in videoRef.value) {
          videoRef.value.srcObject = _mediaStream
        } else {
          // 防止在新的浏览器里使用它，应为它已经不再支持了
          videoRef.value.src = window.URL.createObjectURL(_mediaStream)
        }
        mediaStream.value = _mediaStream
        videoRef.value.onloadedmetadata = () => {
          videoRef.value.play()
        }
      } else {
        throwError('当前不支持此功能，请打开摄像头权限或者更换浏览器！')
      }
    }catch (e) {
      console.dir(e)
      throwError('当前不支持此功能，请打开摄像头权限或者更换浏览器！')
    }
  }

  // 投影视频静音
  const muteVideo = () => {
    videoRef.value.muted = true
    videoRef.value.pause()
  }

  // 开始录制截取视频流
  const start = () => {
    if (errorMessage.value) {
      throwError(errorMessage.value)
      return
    }
    let mediaRecorder
    let options
    if (typeof MediaRecorder.isTypeSupported === 'function') {
      // 根据浏览器来设置编码参数
      if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
        options = {
          MimeType: 'video/webm;codecs=h264'
        }
      } else if (MediaRecorder.isTypeSupported('video/webm;codecs=h264')) {
        options = {
          MimeType: 'video/webm;codecs=h264'
        }
      } else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
        options = {
          MimeType: 'video/webm;codecs=vp8'
        }
      }
      mediaRecorder = new MediaRecorder(mediaStream.value, options)
    } else {
      mediaRecorder = new MediaRecorder(mediaStream.value)
    }
    mediaRecorder.start()
    // 视频录制监听事件
    mediaRecorder.ondataavailable = (e) => {
      // 录制的视频数据有效
      if (e.data && e.data.size > 0) {
        recordedBlobs.value.push(e.data)
      }
    }
    // 停止录像后增加下载视频功能，将视频流转为mp4格式
    mediaRecorder.onstop = () => {
      const blob = new Blob(recordedBlobs.value, {type: 'video/mp4'})
      recordedBlobs.value = []
      // 将视频链接转换完可以用于在浏览器上预览的本地视频
      const videoUrl = window.URL.createObjectURL(blob)
      // 1s下载文件
      setTimeout(() => {
        downloadFile(videoUrl, 'video' + new Date().getTime())
      }, 4000)
    }
  }

  // 停止录制
  const stop = () => {
    if (errorMessage.value) {
      throwError(errorMessage.value)
      return
    }
    if (!videoRef.value?.srcObject) return
    const tracks = videoRef.value.srcObject.getTracks()
    // 关闭摄像头和音频
    tracks.forEach((track) => {
      track.stop()
    })
  }

  // 截取当前这一帧图片,返回base64url
  const screenshot = (canvas) => {
    if (errorMessage.value) {
      throwError(errorMessage.value)
      return
    }
    const context = canvas.getContext('2d')
    canvas.width = videoRef.value.videoWidth
    canvas.height = videoRef.value.videoHeight
    context.drawImage(videoRef.value, 0, 0, canvas.width, canvas.height)
    return canvas.toDataURL('image/jpeg', 1.0)
  }
  return { openCamera, start, stop, screenshot }
}
